package com.tyc.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;

/**
 * @Description: 认证服务器适配器
 * @Author: tyc
 * @CreateDate: 2021/2/6 13:58
 */
@Configuration
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager ;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private UserDetailsService userDetailsService;


    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder() ;
    }

    @Bean
    public TokenStore tokenStore(){
//        return new JdbcTokenStore(dataSource);
        return new JwtTokenStore(jwtTokenEnhancer());
    }

    private JwtAccessTokenConverter jwtTokenEnhancer(){
        /**
         * 对jwt进行签名的key，jwt是明文，签名防篡改。
         * 接收token的人需要用同样的key验签名，需要把这个key通过服务暴漏出去，使用服务的人才能拿到key
         */
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("tyc");
        return converter;
    }
   /**
     * 1，配置客户端应用的信息，让认证服务器知道有哪些客户端应用来申请令牌。
     *
     * ClientDetailsServiceConfigurer：客户端的详情服务的配置
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /////////2--从数据库里读取客户端应用配置信息，需要一个数据源，
        // spring会自动去  oauth_client_details 表里读取客户端信息

        clients.jdbc(dataSource);
    }


    /**
     * 配置客户端应用的信息，让认证服务器知道有哪些客户端应用来申请令牌。
     * 客户端的详情服务的配置
     * @param clients
     * @throws Exception
     */
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.inMemory()//配置在内存里，后面修改为数据库里
//                //~============== 注册【客户端应用】,使客户端应用能够访问认证服务器 ===========
//                .withClient("orderApp")
//                .secret(passwordEncoder().encode("123456"))
//                .scopes("read","write")//orderApp有哪些权限
//                .accessTokenValiditySeconds(3600)//token的有效期
//                .resourceIds("order-server")//资源服务器的id。发给orderApp的token，能访问哪些资源服务器，可以多个
//                .authorizedGrantTypes("password")//授权方式，再给orderApp做授权的时候可以用哪种授权方式授权
//                //~=============客户端应用配置结束 =====================
//                .and()
//                //~============== 注册【资源服务器-订单服务】(因为订单服务需要来认证服务器验令牌),使订单服务也能够访问认证服务器 ===========
//                .withClient("orderService")
//                .secret(passwordEncoder().encode("123456"))
//                .scopes("read","write") //有哪些权限
//                .accessTokenValiditySeconds(3600)
//                .resourceIds("order-server")
//                .authorizedGrantTypes("password")
//        ;
//    }

    /**
     * 配置用户信息
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints
                //这里指定userDetailsService是专门给refresh_token用的，其他的四种授权模式不需要这个
                .userDetailsService(userDetailsService)
                //告诉服务器用自定义的tokenStore里去存取token
                .tokenStore(tokenStore())
                .tokenEnhancer(jwtTokenEnhancer())
                //传给他一个authenticationManager用来校验传过来的用户信息是不是合法的,注进来一个，自己实现
                .authenticationManager(authenticationManager) ;
    }
    //3. 配置资源服务器过来验token 的规则
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        /**
         * 过来验令牌有效性的请求，不是谁都能验的，必须要是经过身份认证的。
         * 所谓身份认证就是，必须携带clientId，clientSecret，否则随便一请求过来验token是不验的
         */
        security.checkTokenAccess("isAuthenticated()") ;
    }
}
